home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
001-025
/
disk_022
/
lemacs
/
search.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-06
|
13KB
|
551 lines
/*
* The functions in this file implement commands that search in the forward
* and backward directions. There are no special characters in the search
* strings. Probably should have a regular expression search, or something
* like that.
*
*/
#include <stdio.h>
#include "estruct.h"
#include "edef.h"
/*
* Search forward. Get a search string from the user, and search, beginning at
* ".", for the string. If found, reset the "." to be just after the match
* string, and [perhaps] repaint the display. Bound to "C-S".
*/
/* string search input parameters */
#define PTBEG 1 /* leave the point at the begining on search */
#define PTEND 2 /* leave the point at the end on search */
forwsearch(f, n)
{
register int status;
/* resolve the repeat count */
if (n == 0)
n = 1;
if (n < 1) /* search backwards */
return(backsearch(f, -n));
/* ask the user for the text of a pattern */
if ((status = readpattern("Search")) != TRUE)
return(status);
/* search for the pattern */
while (n-- > 0) {
if ((status = forscan(&pat[0],PTEND)) == FALSE)
break;
}
/* and complain if not there */
if (status == FALSE)
mlwrite("Not found");
return(status);
}
forwhunt(f, n)
{
register int status;
/* resolve the repeat count */
if (n == 0)
n = 1;
if (n < 1) /* search backwards */
return(backhunt(f, -n));
/* Make sure a pattern exists */
if (pat[0] == 0) {
mlwrite("No pattern set");
return(FALSE);
}
/* search for the pattern */
while (n-- > 0) {
if ((status = forscan(&pat[0],PTEND)) == FALSE)
break;
}
/* and complain if not there */
if (status == FALSE)
mlwrite("Not found");
return(status);
}
/*
* Reverse search. Get a search string from the user, and search, starting at
* "." and proceeding toward the front of the buffer. If found "." is left
* pointing at the first character of the pattern [the last character that was
* matched]. Bound to "C-R".
*/
backsearch(f, n)
{
register int s;
/* resolve null and negative arguments */
if (n == 0)
n = 1;
if (n < 1)
return(forwsearch(f, -n));
/* get a pattern to search */
if ((s = readpattern("Reverse search")) != TRUE)
return(s);
/* and go search for it */
bsearch(f,n);
}
backhunt(f, n) /* hunt backward for the last search string entered */
{
/* resolve null and negative arguments */
if (n == 0)
n = 1;
if (n < 1)
return(forwhunt(f, -n));
/* Make sure a pattern exists */
if (pat[0] == 0) {
mlwrite("No pattern set");
return(FALSE);
}
/* and go search for it */
bsearch(f,n);
}
bsearch(f, n)
{
register LINE *clp;
register int cbo;
register LINE *tlp;
register int tbo;
register int c;
register char *epp;
register char *pp;
/* find a pointer to the end of the pattern */
for (epp = &pat[0]; epp[1] != 0; ++epp)
;
/* make local copies of the starting location */
clp = curwp->w_dotp;
cbo = curwp->w_doto;
while (n-- > 0) {
for (;;) {
/* if we are at the begining of the line, wrap back around */
if (cbo == 0) {
clp = lback(clp);
if (clp == curbp->b_linep) {
mlwrite("Not found");
return(FALSE);
}
cbo = llength(clp)+1;
}
/* fake the <NL> at the end of a line */
if (--cbo == llength(clp))
c = '\n';
else
c = lgetc(clp, cbo);
/* check for a match against the end of the pattern */
if (eq(c, *epp) != FALSE) {
tlp = clp;
tbo = cbo;
pp = epp;
/* scanning backwards through the rest of the
pattern looking for a match */
while (pp != &pat[0]) {
/* wrap across a line break */
if (tbo == 0) {
tlp = lback(tlp);
if (tlp == curbp->b_linep)
goto fail;
tbo = llength(tlp)+1;
}
/* fake the <NL> */
if (--tbo == llength(tlp))
c = '\n';
else
c = lgetc(tlp, tbo);
if (eq(c, *--pp) == FALSE)
goto fail;
}
/* A Match! reset the current cursor */
curwp->w_dotp = tlp;
curwp->w_doto = tbo;
curwp->w_flag |= WFMOVE;
goto next;
}
fail:;
}
next:;
}
return(TRUE);
}
/*
* Compare two characters. The "bc" comes from the buffer. It has it's case
* folded out. The "pc" is from the pattern.
*/
eq(bc, pc)
int bc;
int pc;
{
if ((curwp->w_bufp->b_mode & MDEXACT) == 0) {
if (bc>='a' && bc<='z')
bc -= 0x20;
if (pc>='a' && pc<='z')
pc -= 0x20;
}
if (bc == pc)
return(TRUE);
return(FALSE);
}
/*
* Read a pattern. Stash it in the external variable "pat". The "pat" is not
* updated if the user types in an empty line. If the user typed an empty line,
* and there is no old pattern, it is an error. Display the old pattern, in the
* style of Jeff Lomicka. There is some do-it-yourself control expansion.
* change to using <ESC> to delemit the end-of-pattern to allow <NL>s in
* the search string.
*/
readpattern(prompt)
char *prompt;
{
register int s;
char tpat[NPAT+20];
strcpy(tpat, prompt); /* copy prompt to output string */
strcat(tpat, " ["); /* build new prompt string */
expandp(&pat[0], &tpat[strlen(tpat)], NPAT/2); /* add old pattern */
strcat(tpat, "]<ESC>: ");
s = mlreplyt(tpat, tpat, NPAT, 27); /* Read pattern */
if (s == TRUE) /* Specified */
strcpy(pat, tpat);
else if (s == FALSE && pat[0] != 0) /* CR, but old one */
s = TRUE;
return(s);
}
sreplace(f, n) /* Search and replace (ESC-R) */
int f; /* default flag */
int n; /* # of repetitions wanted */
{
return(replaces(FALSE, f, n));
}
qreplace(f, n) /* search and replace with query (ESC-CTRL-R) */
int f; /* default flag */
int n; /* # of repetitions wanted */
{
return(replaces(TRUE, f, n));
}
/* replaces: search for a string and replace it with another
string. query might be enabled (according to
kind). */
replaces(kind, f, n)
int kind; /* Query enabled flag */
int f; /* default flag */
int n; /* # of repetitions wanted */
{
register int i; /* loop index */
register int s; /* success flag on pattern inputs */
register int slength,
rlength; /* length of search and replace strings */
register int numsub; /* number of substitutions */
register int nummatch; /* number of found matches */
int nlflag; /* last char of search string a <NL>? */
int nlrepl; /* was a replace done on the last line? */
char tmpc; /* temporary character */
char c; /* input char for query */
char tpat[NPAT]; /* temporary to hold search pattern */
LINE *origline; /* original "." position */
int origoff; /* and offset (for . query option) */
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
/* check for negative repititions */
if (f && n < 0)
return(FALSE);
/* ask the user for the text of a pattern */
if ((s = readpattern(
(kind == FALSE ? "Replace" : "Query replace"))) != TRUE)
return(s);
strcpy(&tpat[0], &pat[0]); /* salt it away */
/* ask for the replacement string */
strcpy(&pat[0], &rpat[0]); /* set up default string */
if ((s = readpattern("with")) == ABORT)
return(s);
/* move everything to the right place and length them */
strcpy(&rpat[0], &pat[0]);
strcpy(&pat[0], &tpat[0]);
slength = strlen(&pat[0]);
rlength = strlen(&rpat[0]);
/* set up flags so we can make sure not to do a recursive
replace on the last line */
nlflag = (pat[slength - 1] == '\n');
nlrepl = FALSE;
/* build query replace question string */
strcpy(tpat, "Replace '");
expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3);
strcat(tpat, "' with '");
expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3);
strcat(tpat, "'? ");
/* save original . position */
origline = curwp->w_dotp;
origoff = curwp->w_doto;
/* scan through the file */
numsub = 0;
nummatch = 0;
while ((f == FALSE || n > nummatch) &&
(nlflag == FALSE || nlrepl == FALSE)) {
/* search for the pattern */
if (forscan(&pat[0],PTBEG) != TRUE)
break; /* all done */
++nummatch; /* increment # of matches */
/* check if we are on the last line */
nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);
/* check for query */
if (kind) {
/* get the query */
mlwrite(&tpat[0], &pat[0], &rpat[0]);
qprompt:
update(); /* show the proposed place to change */
c = (*term.t_getchar)(); /* and input */
mlwrite(""); /* and clear it */
/* and respond appropriately */
switch (c) {
case 'y': /* yes, substitute */
case ' ':
break;
case 'n': /* no, onword */
forwchar(FALSE, 1);
continue;
case '!': /* yes/stop asking */
kind = FALSE;
break;
case '.': /* abort! and return */
/* restore old position */
curwp->w_dotp = origline;
curwp->w_doto = origoff;
curwp->w_flag |= WFMOVE;
case BELL: /* abort! and stay */
mlwrite("Aborted!");
return(FALSE);
default: /* bitch and beep */
(*term.t_beep)();
case '?': /* help me */
mlwrite("(Y)es, (N)o, (!)Do the rest, (^G)Abort, (.)Abort back, (?)Help: ");
goto qprompt;
}
}
/* delete the sucker */
if (ldelete(slength, FALSE) != TRUE) {
/* error while deleting */
mlwrite("ERROR while deleteing");
return(FALSE);
}
/* and insert its replacement */
for (i=0; i<rlength; i++) {
tmpc = rpat[i];
s = (tmpc == '\n' ? lnewline() : linsert(1, tmpc));
if (s != TRUE) {
/* error while inserting */
mlwrite("Out of memory while inserting");
return(FALSE);
}
}
numsub++; /* increment # of substitutions */
}
/* and report the results */
mlwrite("%d substitutions",numsub);
return(TRUE);
}
forscan(patrn,leavep) /* search forward for a <patrn> */
char *patrn; /* string to scan for */
int leavep; /* place to leave point
PTBEG = begining of match
PTEND = at end of match */
{
register LINE *curline; /* current line during scan */
register int curoff; /* position within current line */
register LINE *lastline; /* last line position during scan */
register int lastoff; /* position within last line */
register int c; /* character at current position */
register LINE *matchline; /* current line during matching */
register int matchoff; /* position in matching line */
register char *patptr; /* pointer into pattern */
/* setup local scan pointers to global "." */
curline = curwp->w_dotp;
curoff = curwp->w_doto;
/* scan each character until we hit the head link record */
while (curline != curbp->b_linep) {
/* save the current position in case we need to
restore it on a match */
lastline = curline;
lastoff = curoff;
/* get the current character resolving EOLs */
if (curoff == llength(curline)) { /* if at EOL */
curline = lforw(curline); /* skip to next line */
curoff = 0;
c = '\n'; /* and return a <NL> */
} else
c = lgetc(curline, curoff++); /* get the char */
/* test it against first char in pattern */
if (eq(c, patrn[0]) != FALSE) { /* if we find it..*/
/* setup match pointers */
matchline = curline;
matchoff = curoff;
patptr = &patrn[0];
/* scan through patrn for a match */
while (*++patptr != 0) {
/* advance all the pointers */
if (matchoff == llength(matchline)) {
/* advance past EOL */
matchline = lforw(matchline);
matchoff = 0;
c = '\n';
} else
c = lgetc(matchline, matchoff++);
/* and test it against the pattern */
if (eq(*patptr, c) == FALSE)
goto fail;
}
/* A SUCCESSFULL MATCH!!! */
/* reset the global "." pointers */
if (leavep == PTEND) { /* at end of string */
curwp->w_dotp = matchline;
curwp->w_doto = matchoff;
} else { /* at begining of string */
curwp->w_dotp = lastline;
curwp->w_doto = lastoff;
}
curwp->w_flag |= WFMOVE; /* flag that we have moved */
return(TRUE);
}
fail:; /* continue to search */
}
/* we could not find a match */
return(FALSE);
}
/* expandp: expand control key sequences for output */
expandp(srcstr, deststr, maxlength)
char *srcstr; /* string to expand */
char *deststr; /* destination of expanded string */
int maxlength; /* maximum chars in destination */
{
char c; /* current char to translate */
/* scan through the string */
while ((c = *srcstr++) != 0) {
if (c == '\n') { /* its an EOL */
*deststr++ = '<';
*deststr++ = 'N';
*deststr++ = 'L';
*deststr++ = '>';
maxlength -= 4;
} else if (c < 0x20 || c == 0x7f) { /* control character */
*deststr++ = '^';
*deststr++ = c ^ 0x40;
maxlength -= 2;
} else if (c == '%') {
*deststr++ = '%';
*deststr++ = '%';
maxlength -= 2;
} else { /* any other character */
*deststr++ = c;
maxlength--;
}
/* check for maxlength */
if (maxlength < 4) {
*deststr++ = '$';
*deststr = '\0';
return(FALSE);
}
}
*deststr = '\0';
return(TRUE);
}